import urllib2
import hashlib
import time

from django.contrib.auth.decorators import login_required
from django.template import RequestContext
from django.http import HttpResponse
from django.core.servers.basehttp import FileWrapper
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
from django import forms

from astrometry.blind.plotstuff import *
from PIL import Image

resource_directory = 'resources/'

class Annotator():

    default_font_size       = 10
    default_font_color      = 'green'
    default_show_grid       = True
    default_grid_color      = 'gray'
    default_grid_tick_scale = 0.1
    default_grid_label_scale = 0.2

    def plot(self, imgfn, wcsfn, outfn, font_size=default_font_size, font_color='green',show_grid=True,
        grid_color=default_grid_color, tick_scale=default_grid_tick_scale, label_scale=default_grid_label_scale
    ):
        # annotate using plotstuff
        plot = Plotstuff()
        plot.wcs_file = str(wcsfn)
        plot.outformat = PLOTSTUFF_FORMAT_JPG
        plot.outfn = str(outfn)
        plotstuff_set_size_wcs(plot.pargs)
        img = plot.image
        img.set_file(str(imgfn))
        plot.plot('image')

        if(show_grid):
            plot.color = str(grid_color)
            plot.plot_grid(tick_scale,tick_scale,label_scale,label_scale)

        ann = plot.annotations
        ann.NGC = True
        ann.constellations = True
        ann.bright = True
        ann.ngc_fraction = 0.
        #if opt.hdcat:
        #    ann.HD = True
        #    ann.hd_catalog = opt.hdcat
        plot.color = str(font_color)
        plot.fontsize = font_size
        plot.lw = 2.

        plot.plot('annotations')
        plot.write()

class AnnotatorForm(forms.Form):
    color_choices = (
        ('green','green'),
        ('white','white'),
        ('black','black'),
        ('red','red'),
        ('blue','blue'),
        ('cyan','cyan'),
        ('yellow','yellow'),
        ('magenta','magenta'),
        ('gray','gray'),
    )

    job_id                  = forms.CharField(max_length=255)
    font_size               = forms.IntegerField(min_value=1,initial=Annotator.default_font_size)
    font_color              = forms.ChoiceField(choices=color_choices, initial=Annotator.default_font_color)
    show_grid               = forms.BooleanField(
                                initial=Annotator.default_show_grid,
                                required=False,
                                widget=forms.CheckboxInput(
                                    attrs={'onclick':"toggleGridOpts()"}
                                ))
    grid_color              = forms.ChoiceField(choices=color_choices, initial=Annotator.default_grid_color, required=False)
    plot_grid_tick_scale    = forms.FloatField(min_value=0,initial=Annotator.default_grid_tick_scale, required=False)
    plot_grid_label_scale   = forms.FloatField(min_value=0,initial=Annotator.default_grid_label_scale,required=False)


def home(request):
    context = {}
    context.update({'logged_in':request.user.is_authenticated()})
    if request.user.is_authenticated():
        context.update({'username':request.user.username})
        context.update({'user_full_name':request.user.get_full_name()})

        context.update(csrf(request))
        custom_stylesheets = ['annotation_form.css']

        custom_scripts = []
        custom_scripts.append(
            {'type':'text/javascript','filename':'jquery-1.5.2.js'}
        )
        custom_scripts.append(
            {'type':'text/javascript', 'filename':'annotator_form.js'}
        )

        context.update({'custom_stylesheets':custom_stylesheets})
        context.update({'custom_scripts':custom_scripts})

        form = AnnotatorForm()
        context.update({'form':form})

        if request.method == 'POST':
            custom_stylesheets.append('response.css')
            layout = 'home/response.html'
            request_form = AnnotatorForm(request.POST)
            context.update({
                'default_font_size':Annotator.default_font_size,
                'default_grid_tick_scale':Annotator.default_grid_tick_scale,
                'default_grid_label_scale':Annotator.default_grid_label_scale
            })
            if(request_form.is_valid() and request_form.clean()):
                # assuming properly formatted urls for now
                image_url_ok = False
                try:
                    context.update({'request_form':request_form})

                    job_url = 'http://live.astrometry.net/status.php?job=' + request_form.cleaned_data['job_id'].strip()

                    # make sure the job id is ok
                    u = urllib2.urlopen(job_url)
                    if('Invalid' not in u.read()):
                        u.close()
                        image_url = job_url + '&get=fullsize.png'
                        image_file_ext = image_url.split('.')[-1]
                        wcs_url = job_url + '&get=wcs.fits'

                        # get options
                        font_size = Annotator.default_font_size
                        font_color = Annotator.default_font_color
                        grid_color = Annotator.default_grid_color
                        tick_scale = Annotator.default_grid_tick_scale
                        label_scale = Annotator.default_grid_label_scale
                        show_grid = request_form.cleaned_data['show_grid']

                        if request_form.cleaned_data['font_size']:
                            font_size = request_form.cleaned_data['font_size']
                        if request_form.cleaned_data['font_color']:
                            font_color = request_form.cleaned_data['font_color']
                        if request_form.cleaned_data['grid_color']:
                            grid_color = request_form.cleaned_data['grid_color']
                        if request_form.cleaned_data['plot_grid_tick_scale']:
                            tick_scale = request_form.cleaned_data['plot_grid_tick_scale']
                        if request_form.cleaned_data['plot_grid_label_scale']:
                            label_scale = request_form.cleaned_data['plot_grid_label_scale']

                        # make a (probably) unique filename for local copies of the
                        # resources, and make the local copies

                        # output filename dependent on input files, and the options
                        # used
                        local_image_filename = hashlib.md5(image_url).hexdigest() \
                            + '.' + image_file_ext
                        local_wcs_filename = hashlib.md5(wcs_url).hexdigest() \
                            + '.fits'
                        gridOptsHash = hashlib.md5(
                            str(grid_color) +
                            str(tick_scale) +
                            str(label_scale)
                        ).hexdigest()

                        optionsHash = str(
                            hashlib.md5(
                                str(font_size) + font_color +
                                    (gridOptsHash if show_grid else '')
                            ).hexdigest())

                        local_output_filename = hashlib.md5(
                            image_url + wcs_url + optionsHash
                        ).hexdigest() + '.jpg'

                        wcsfn = resource_directory + local_wcs_filename
                        imgfn = resource_directory + local_image_filename
                        outfn = resource_directory + local_output_filename
                        local_preview_filename = 'prv-' + local_output_filename
                        previewfn = resource_directory + local_preview_filename

                        local_image = open(imgfn, 'w')
                        local_wcs = open(wcsfn, 'w')
                        u = urllib2.urlopen(image_url)
                        image_url_ok = True # used to determine source of error, if any

                        local_image.write(u.read())
                        u.close()
                        u = urllib2.urlopen(wcs_url)
                        local_wcs.write(u.read())
                        u.close()
                        local_image.close()
                        local_wcs.close()

                        annotator = Annotator()
                        annotator.plot(imgfn,wcsfn,outfn,font_size,font_color,show_grid,
                            grid_color,tick_scale,label_scale)

                        size = 400,400
                        preview_image = Image.open(outfn)
                        preview_image.thumbnail(size, Image.ANTIALIAS)
                        preview_image.save(previewfn)

                        context.update({
                            'out_filename':local_output_filename,
                            'preview_filename':local_preview_filename
                        })
                    else:
                        context.update({'error':'Invalid job id'})

                except ValueError:
                    error = ''
                    if not image_url_ok:
                        error = 'Sorry, we could not open the image URL you gave us'
                    else:
                        error = 'Sorry, we could not open the wcs URL you gave us'
                    context.update({'error':error})
            else:
            # there's problems with the specified options
                context.update({'error':'Invalid option value(s)'})
        else:
        # request method is not POST; the user hasn't specified options
            layout = 'home/default.html'
    else:
    # user is not authenticated
        layout = 'home/login.html'

    return render_to_response(layout, context,
        context_instance=RequestContext(request))

@login_required
def retrieve(request):
    context = {}
    layout = 'no_output.html'
    if request.GET.__getitem__('fn'):
        try:
            outfn = resource_directory + request.GET.__getitem__('fn')
            local_output = open(outfn)
            response = HttpResponse(FileWrapper(local_output),
                content_type='image/jpeg')
            response['Content-Disposition'] = 'attachment; filename=output.jpg'
            return response;
        except ValueError:
            return render_to_response(layout, context)
    else:
        return render_to_response(layout, context)
